#!/usr/bin/env python3
"""
HTTPS服务器脚本
支持WebXR所需的安全连接
"""

import http.server
import ssl
import socketserver
import os
import sys
import argparse
from pathlib import Path

class HTTPSHandler(http.server.SimpleHTTPRequestHandler):
    """自定义HTTPS处理器，添加必要的安全头"""
    
    def end_headers(self):
        # 添加安全头以支持WebXR
        self.send_header('Cross-Origin-Embedder-Policy', 'require-corp')
        self.send_header('Cross-Origin-Opener-Policy', 'same-origin')
        # 允许跨域资源被其它源安全嵌入（满足 COEP 要求的 CORP）
        self.send_header('Cross-Origin-Resource-Policy', 'cross-origin')
        # 兼容部分工具的标准 CORS 访问（用于外部 Viewer 拉取本地 PLY）
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'GET, OPTIONS')
        self.send_header('Access-Control-Allow-Headers', 'Content-Type')
        self.send_header('Permissions-Policy', 'xr-spatial-tracking=*')
        super().end_headers()
    
    def log_message(self, format, *args):
        """自定义日志格式"""
        print(f"🔒 HTTPS [{self.log_date_time_string()}] {format % args}")

def create_https_server(port=8081, host='0.0.0.0', cert_file='server.crt', key_file='server.key'):
    """创建HTTPS服务器"""
    
    # 检查证书文件
    if not os.path.exists(cert_file):
        print(f"❌ 错误: 证书文件 {cert_file} 不存在")
        return None
    
    if not os.path.exists(key_file):
        print(f"❌ 错误: 私钥文件 {key_file} 不存在")
        return None
    
    try:
        # 创建HTTP服务器
        with socketserver.TCPServer((host, port), HTTPSHandler) as httpd:
            # 配置SSL上下文
            context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
            context.load_cert_chain(cert_file, key_file)
            
            # 包装socket以支持SSL
            httpd.socket = context.wrap_socket(httpd.socket, server_side=True)
            
            print(f"🚀 HTTPS服务器启动成功!")
            print(f"📍 本地访问: https://localhost:{port}")
            print(f"🌐 网络访问: https://{get_local_ip()}:{port}")
            print(f"🥽 WebXR支持: ✅ 已启用")
            print(f"📁 服务目录: {os.getcwd()}")
            print(f"🔒 SSL证书: {cert_file}")
            print("=" * 50)
            print("按 Ctrl+C 停止服务器")
            print("=" * 50)
            
            # 启动服务器
            httpd.serve_forever()
            
    except ssl.SSLError as e:
        print(f"❌ SSL错误: {e}")
        print("💡 提示: 请检查证书文件是否有效")
        return None
    except OSError as e:
        if e.errno == 48:  # Address already in use
            print(f"❌ 端口 {port} 已被占用")
            print(f"💡 提示: 请尝试其他端口或停止占用该端口的进程")
        else:
            print(f"❌ 网络错误: {e}")
        return None
    except KeyboardInterrupt:
        print("\n🛑 服务器已停止")
        return None

def get_local_ip():
    """获取本地IP地址"""
    import socket
    try:
        # 连接到一个远程地址来获取本地IP
        with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
            s.connect(("8.8.8.8", 80))
            return s.getsockname()[0]
    except:
        return "127.0.0.1"

def generate_self_signed_cert(cert_file='server.crt', key_file='server.key'):
    """生成自签名证书（如果不存在）"""
    try:
        from cryptography import x509
        from cryptography.x509.oid import NameOID
        from cryptography.hazmat.primitives import hashes, serialization
        from cryptography.hazmat.primitives.asymmetric import rsa
        import datetime
        
        # 生成私钥
        private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048,
        )
        
        # 创建证书
        subject = issuer = x509.Name([
            x509.NameAttribute(NameOID.COUNTRY_NAME, "CN"),
            x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "State"),
            x509.NameAttribute(NameOID.LOCALITY_NAME, "City"),
            x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Organization"),
            x509.NameAttribute(NameOID.COMMON_NAME, "localhost"),
        ])
        
        cert = x509.CertificateBuilder().subject_name(
            subject
        ).issuer_name(
            issuer
        ).public_key(
            private_key.public_key()
        ).serial_number(
            x509.random_serial_number()
        ).not_valid_before(
            datetime.datetime.utcnow()
        ).not_valid_after(
            datetime.datetime.utcnow() + datetime.timedelta(days=365)
        ).add_extension(
            x509.SubjectAlternativeName([
                x509.DNSName("localhost"),
                x509.DNSName("127.0.0.1"),
                x509.IPAddress(ipaddress.IPv4Address("127.0.0.1")),
            ]),
            critical=False,
        ).sign(private_key, hashes.SHA256())
        
        # 保存证书
        with open(cert_file, "wb") as f:
            f.write(cert.public_bytes(serialization.Encoding.PEM))
        
        # 保存私钥
        with open(key_file, "wb") as f:
            f.write(private_key.private_bytes(
                encoding=serialization.Encoding.PEM,
                format=serialization.PrivateFormat.PKCS8,
                encryption_algorithm=serialization.NoEncryption()
            ))
        
        print(f"✅ 自签名证书已生成: {cert_file}, {key_file}")
        return True
        
    except ImportError:
        print("❌ 无法生成证书: 缺少 cryptography 库")
        print("💡 请运行: pip install cryptography")
        return False
    except Exception as e:
        print(f"❌ 生成证书失败: {e}")
        return False

def main():
    parser = argparse.ArgumentParser(description='启动支持WebXR的HTTPS服务器')
    parser.add_argument('--port', '-p', type=int, default=8080, help='端口号 (默认: 8080)')
    parser.add_argument('--host', type=str, default='0.0.0.0', help='主机地址 (默认: 0.0.0.0)')
    parser.add_argument('--cert', type=str, default='server.crt', help='证书文件路径')
    parser.add_argument('--key', type=str, default='server.key', help='私钥文件路径')
    parser.add_argument('--generate-cert', action='store_true', help='生成自签名证书')
    
    args = parser.parse_args()
    
    # 如果需要生成证书
    if args.generate_cert:
        if generate_self_signed_cert(args.cert, args.key):
            print("证书生成完成，现在启动服务器...")
        else:
            print("证书生成失败，退出...")
            sys.exit(1)
    
    # 启动HTTPS服务器
    create_https_server(args.port, args.host, args.cert, args.key)

if __name__ == '__main__':
    main()